(function (window, gapi, Config) {
  "use strict";
  //var configInitialized = false;

  var dn = {};

  dn.SaveFile = function (fileId, fileMetadata, data, callback) {
    var boundary = dn.MakeBoundary();
    var delimiter = "\r\n--" + boundary + "\r\n";
    var close_delim = "\r\n--" + boundary + "--";
    var userData = [].slice.call(arguments, 4);

    var messageBody = delimiter +
      'Content-Type: application/json\r\n' +
      '\r\n' + JSON.stringify(fileMetadata ? fileMetadata : {});

    if (data) {
      messageBody += delimiter +
        'Content-Type: application/octet-stream\r\n' +
        'Content-Transfer-Encoding: base64\r\n' +
      //'\r\n' + btoa(unescape(encodeURIComponent(data)));
      '\r\n' + data;
    }
    messageBody += close_delim;

    var request = gapi.client.request({
      path: '/upload/drive/v2/files/' + (fileId ? fileId : ""),
      method: (fileId ? 'PUT' : 'POST'),
      params: {
        'uploadType': 'multipart'
      },
      headers: {
        'Content-Type': 'multipart/mixed; boundary="' + boundary + '"'
      },
      body: messageBody
    });

    request.execute(function () {
      callback.apply(this, userData);
    });
  };

  dn.MakeBoundary = function () {
    //for MIME protocol, require a boundary that doesn't exist in the message content.
    //we could check explicitly, but this is essentially guaranteed to be fine:
    // e.g. "13860126288389.206091766245663"
    return (new Date()).getTime() + "" + Math.random() * 10;
  };

  var Auth = {
    autoInit: function () {
      var _this = this;
      var authLoadInterval = setInterval(function () {
        if (gapi.auth) {
          _this.run(false);
          clearInterval(authLoadInterval);
        }
      }, 500);
    },

    run: function (force, success) {
      success = success || function () {};
      gapi.auth.authorize({
        client_id: '51425356979-ggigmvrs9mqgd85qhm1h2qddaelmcbue.apps.googleusercontent.com',
        immediate: true,
        response_type: 'token',
        //approval_prompt: 'force',
        include_granted_scopes: false,
        //prompt: 'select_account',
        scope: ['https://www.googleapis.com/auth/drive', 'https://sites.google.com/feeds/']
      }, success);
    }
  };

  window.addEventListener("message", function (event) {
    if (event.origin.match(/sites-opensocial\.googleusercontent\.com$/)) {
      var data = event.data;
      if (!data || !data.message) {
        return;
      }

      switch (data.message) {
        /*
    case 'setConfigFolderId':
      {
        if (!configInitialized) {
          Config.config_folder = data.configFolderId;
        }

        window.opener && window.opener.postMessage({
          message: 'received'
        }, '*');

        break;
      }
      */
      }
    }
  }, false);

  var app = angular.module('app', ['ui.sortable']);

  app.filter('range', function () {
    return function (input, total) {
      total = parseInt(total, 10);
      for (var i = 0; i < total; i++) {
        input.push(i);
      }
      return input;
    };
  });

  app.directive('colorSelector', function () {
    return function ($scope, $element) {
      setTimeout(function () {
        $($element).spectrum({
          preferredFormat: 'rgb',
          showInitial: true
        });
      });
    };
  });

  app.directive('divColorStyleSetter', function () {
    return function ($scope) {
      var setColorStyle = function (sub) {
        var customClass = sub ? 'custom-sub' : 'custom';
        var name = sub ? 'sub-name' : 'name';
        return function (val) {
          var customHover = "." + name + " ." +
            customClass + ":hover {color: " + val.textSurvol +
            ";background-color: " + val.backSurvol + "}";
          var custom = "." + name + " ." + customClass +
            " {color: " + val.textMenu + ";background-color: " +
            val.backMenu + "}";
          var styleId = 'hover-' + customClass;
          if ($('#' + styleId).length === 0) {
            $('<style/>').attr('id', styleId).prependTo($('#menus-editor'));
          }

          $('#' + styleId).html(custom + customHover);
        };
      };

      $scope.$watchCollection('menus.color.menu', setColorStyle(false));
      $scope.$watchCollection('menus.color.subMenu', setColorStyle(true));

      setColorStyle(false)($scope.menus.color.menu);
      setColorStyle(true)($scope.menus.color.subMenu);
    };
  });

  /*
  app.directive('divTooltip', function () {
    return function ($scope, $element) {
      setTimeout(function () {
        $($element).tooltip();
      });
    };
  });
  */

  app.directive('menusSetting', function () {
    return {
      restrict: 'C',
      controller: function ($scope) {
        $scope.retrievingPages = true;
        $scope.retrievePages = function () {
          // TODO: change
          // var domain = 'econsulting.fr'; //"site" for gmail account
          // var site = 'lab';

          var client = new google.gdata.client.GoogleService('site',
            'chronopost');
          client.setHeaders({
            'Authorization': gapi.auth.getToken().access_token
          });
          var pages = {};
          var href = ['https://sites.google.com/feeds/content', $scope.domain,
            $scope.site
          ].join('/') + "?";
          var query = {
            'max-results': '100',
            'kind': 'announcement,announcementspage,filecabinet,listpage,webpage'
          };

          for (var name in query) {
            href += "&" + name + '=' + query[name];
          }

          var findParent = function (page) {
            for (var index in page.link) {
              if (page.link[index].rel ===
                "http://schemas.google.com/sites/2008#parent") {
                var parts = page.link[index].href.split('/');
                return parts[parts.length - 1];
              }
            }

            return null;
          };

          var getId = function (page) {
            var parts = page.id.$t.split('/');
            return parts[parts.length - 1];
          };

          var getAlternate = function (page) {
            for (var index in page.link) {
              if (page.link[index].rel === "alternate") {
                return page.link[index].href;
              }
            }
          };

          var getTitle = function (page) {
            return page.title.$t;
          };

          var listPages = function (href) {
            client.getFeed(href, function (data) {
              var index;
              var feed = data.feed;
              for (index in feed.entry) {
                pages[getId(feed.entry[index])] = feed.entry[index];
              }

              var end = true;
              // retrieve pages
              if (feed.link && feed.link.length) {
                for (index = 0; index < feed.link.length; index++) {
                  if (feed.link[index].rel === 'next') {
                    listPages(feed.link[index].href);
                    end = false;
                    break;
                  }
                }
              }

              if (end) {
                var menus = {};
                var id;

                // build tree
                for (id in pages) {
                  var parent = findParent(pages[id]);
                  var skip = false;
                  while (parent) {
                    pages[parent].children = pages[parent].children || {};

                    if (pages[parent].children[id]) {
                      skip = true;
                      break;
                    }

                    pages[parent].children[id] = pages[id];
                    id = parent;
                    parent = findParent(pages[id]);
                  }

                  if (!skip && !menus[id]) {
                    menus[id] = pages[id];
                  }
                }

                var newItems = [];
                var oldItems = $scope.menus.items;
                var item;
                var subs;
                var child;
                var subIndex;

                // merge old settings
                for (index in oldItems) {
                  if (item = menus[oldItems[index].id]) {
                    subs = oldItems[index].subs;
                    var children = item.children;
                    var newSubs = [];
                    for (subIndex in subs) {
                      child = children[subs[subIndex].id];
                      if (child) {
                        newSubs.push({
                          name: getTitle(child),
                          id: getId(child),
                          link: getAlternate(child)
                        });

                        child.$added = true;
                      }
                    }

                    for (id in children) {
                      child = children[id];
                      if (!child.$added) {
                        newSubs.push({
                          name: getTitle(child),
                          id: getId(child),
                          link: getAlternate(child)
                        });
                        child.$added = true;
                      }
                    }

                    newItems.push({
                      customMenuColor: oldItems[index].customMenuColor,
                      customSubMenuColor: oldItems[index].customSubMenuColor,
                      wrap: oldItems[index].wrap,
                      name: getTitle(item),
                      link: getAlternate(item),
                      id: getId(item),
                      subs: newSubs
                    });

                    item.$added = true;
                  }
                }

                // Add new added menus
                for (id in menus) {
                  item = menus[id];
                  if (!item.$added) {
                    subs = [];
                    for (subIndex in item.children) {
                      child = item.children[subIndex];
                      subs.push({
                        name: getTitle(child),
                        link: getAlternate(child),
                        id: getId(child)
                      });
                    }

                    newItems.push({
                      customMenuColor: false,
                      customSubMenuColor: false,
                      wrap: false,
                      link: getAlternate(item),
                      id: getId(item),
                      subs: subs,
                      name: getTitle(item)
                    });
                  }
                }

                $scope.$apply(function () {
                  $scope.retrievingPages = false;
                  $scope.menus.items = newItems;
                });
              }
            });
          };

          listPages(href);
        };

        $scope.retrievePages();
      }
    };
  });

  app.controller('editor', function ($scope, $timeout, $location) {
    var currentEditImage;
    var getSearch = function (query) {
      var search = document.location.search;
      var regex = new RegExp(query + '=(.*?)($|&)');
      var ret = search.match(regex);
      if (ret) {
        return ret[1];
      }
    };

    $scope.domain = getSearch('domain');
    $scope.site = getSearch('site');

    $scope.images = Config.raw.images || [];
    $scope.menus = Config.raw.menus || {
      color: {
        menu: {
          textMenu: 'rgb(0,0,0)',
          backMenu: 'rgb(255,255,255)',
          textSurvol: 'rgb(70,0,0)',
          backSurvol: 'rgb(170, 255, 255)'
        },
        subMenu: {
          textSurvol: 'rgb(0,0,0)',
          backSurvol: 'rgb(170,25,170)',
          textMenu: 'rgb(70,0,0)',
          backMenu: 'rgb(170, 255, 255)'
        }
      },
      items: []
    };

    var originImages = angular.copy($scope.images);
    var originMenus = angular.copy($scope.menus);

    $scope.goLeft = function (index) {
      var tmp = $scope.images[index];
      $scope.images[index] = $scope.images[index - 1];
      $scope.images[index - 1] = tmp;
    };

    $scope.goRight = function (index) {
      var tmp = $scope.images[index];
      $scope.images[index] = $scope.images[index + 1];
      $scope.images[index + 1] = tmp;
    };

    $scope.removePicture = function (image) {
      $scope.images.splice($scope.images.indexOf(image), 1);
      if (image === currentEditImage) {
        $scope.clearEditor();
      }
    };

    $('.container').on('change', '.image-input', function () {
      var file;
      if (event.target.files) {
        file = event.target.files[0];
      } else if (event.target.value) {
        file = event.target.value;
      } else {
        return;
      }

      var _event = event;

      var reader = new FileReader();
      reader.onload = (function () {
        return function (e) {
          var img = new Image();
          img.onload = function () {
            var _this = this;
            $scope.$apply(function () {
              $scope.images.push({
                src: e.target.result,
                ratio: 200 / _this.width,
                left: 0,
                top: 0,
                width: _this.width,
                height: _this.height
              });
            });
          };
          img.src = e.target.result;
          $(_event.target).val("");
        };
      })(file);

      reader.readAsDataURL(file);
    });

    $scope.addPicture = function () {
      $('.image-input').trigger('click');
    };

    $scope.clearEditor = function () {
      $('.crop-container').html('');
    };

    $scope.reset = function () {
      $scope.images = angular.copy(originImages);
      $scope.menus = angular.copy(originMenus);
      $scope.clearEditor();
    };

    $scope.save = function () {
      var images = angular.copy($scope.images);
      var menus = angular.copy($scope.menus);
      var toSave = 0;
      var saved = 0;
      var saveConfigFile = function () {
        $scope.message = "Saving configuration...";
        Config.raw.images = images;
        Config.raw.menus = menus;
        var request = gapi.client.request({
          path: '/drive/v2/files/' + Config.getConfigFolderId() + '/children',
          params: {
            q: "title = 'config.json'"
          }
        });

        request.execute(function (data) {
          var fileId;
          if (data.items.length === 1) {
            fileId = data.items[0].id;
          } else {
            $scope.$apply(function () {
              $scope.saving = false;
              $scope.message =
                "Failed to save onfiguration. Please check if 'config.json' exists in folder: " +
                Config.getConfigFolderId();
            });
            return;
          }

          dn.SaveFile(
            fileId, {
              mimeType: 'text/plain',
              title: 'config.json',
              parents: [{
                id: Config.getConfigFolderId()
              }]
            },
            btoa(unescape(encodeURIComponent(JSON.stringify(Config.raw,
              null, 2)))),
            function () {
              $scope.$apply(function () {
                $scope.saving = false;
                $scope.message = "Configuration saved.";
                $timeout(function () {
                  $scope.message = "";
                }, 3000);
                window.opener && window.opener.postMessage({
                  message: 'update'
                }, '*');
              });
            }
          );
        });
      };

      $scope.saving = true;

      for (var index in images) {
        var src = images[index].src;
        if (!src.match(/^http/)) {
          toSave += 1;
          var result = src.match(/data:(.*);base64,(.*)/);
          var title = 'image' + '.' + dn.MakeBoundary() + '.' + result[1].split(
            '/')[1];
          dn.SaveFile(null, {
            title: title,
            parents: [{
              id: Config.getConfigFolderId()
            }],
            mimeType: result[1]
          }, result[2], function (index, title) {
            $scope.$apply(function () {
              saved += 1;
              images[index].src = Config.getStaticFile(title);
              if (toSave === saved) {
                $scope.images = images;
                saveConfigFile();
              }
            });
          }, index, title);
        }
      }

      if (!toSave) {
        saveConfigFile();
      } else {
        $scope.message = "Uploading pictures...";
      }
    };

    $scope.editPicture = function (index) {
      $scope.clearEditor();
      currentEditImage = $scope.images[index];
      var image = currentEditImage;
      var img = $('.frieze-image img')[index];
      var ratio = 1038 / img.naturalWidth;
      var width, height;

      width = img.naturalWidth * ratio;
      height = img.naturalHeight * ratio;
      var jcropAPI;

      $('.crop-container').append(
        $('<img/>')
        .addClass('origin-image')
        .attr('src', $scope.images[index].src)
        .css({
          height: height,
          width: width
        })
        .on('load', function () {
          $(this).Jcrop({
            aspectRatio: 200 / 130,
            onChange: function (c) {
              if (c.h === 0 || c.w === 0) {
                return;
              }

              $scope.$apply(function () {
                var wRatio = 200 / (c.w / ratio);
                image.width = img.naturalWidth;
                image.height = img.naturalHeight;
                image.ratio = wRatio;
                image.left = -(c.x / ratio * wRatio);
                image.top = -(c.y / ratio * wRatio);
              });
            }
          }, function () {
            jcropAPI = this;
            var w = 200 * ratio / image.ratio;
            var x = (-image.left) / image.ratio * ratio;
            var y = (-image.top) / image.ratio * ratio;
            var h = 130 * ratio / image.ratio;

            jcropAPI.setSelect([
              x, y, x + w, y + h
            ]);
          });
        })
      );
    };

    //Menus

    $scope.addMenu = function (menu, name, link) {
      var parentMenu = menu && menu.subs || $scope.menus.items;
      var newMenu = {
        name: name,
        link: link
      };

      if (!menu) {
        newMenu.customMenuColor = false;
        newMenu.wrap = false;
        newMenu.subs = [];
        newMenu.customSubMenuColor = false;
      }

      parentMenu.push(newMenu);
    };

    $scope.removeMenu = function (parent, menu) {
      parent = parent && parent.subs || $scope.menus.items;
      parent = parent.splice(parent.indexOf(menu), 1);
    };

    $scope.getMenuColor = function (custom, sub) {
      if (custom) {
        var color;
        if (!sub) {
          color = $scope.menus.color.menu;
        } else {
          color = $scope.menus.color.subMenu;
        }

        return {
          color: color.textMenu,
          'background-color': color.backMenu
        };
      }
    };
  });

  {
    var interval = setInterval(function () {
      if (gapi.auth && google.gdata) {
        gapi.client.setApiKey('AIzaSyDCwyEqmfODGqom2lLCJ6JoVnU1U5jaKNo');
        clearInterval(interval);
        Auth.run(false, function (token) {
          if (!token) {
            window.close();
          }

          /*
          if (!Config.config_folder && document.location.host.match(
            /(127\.0\.0\.1)|localhost/)) {
            Config.config_folder = '0B16SpQHxHslBWExGZkRzMnE0Mk0';
          }
          */

          Config.load(function () {
            $('body').show();
            angular.bootstrap(angular.element($('body')), ['app']);
          }, function () {
            //Config.raw = {
            //  images: []
            //};
            $('body').show();
            angular.bootstrap(angular.element($('body')), ['app']);
          });
        });
      }
    }, 300);
  }
})(window, window.gapi, window.Config);
